package dev.ece.core.light;

import org.lwjgl.opengl.GL20;

import dev.ece.util.lib.Vector3f;
import dev.ece.util.lib.Vector4f;

/**
 * 光源
 * @author 飘渺青衣
 * <b>E-mail：</b>3375758@qq.com
 */
public class Light {

	public static boolean LIGHTING = true;
	
	public static int MAX_LIGHT_COUNT = 10;
	
	private boolean enable = true;
	/**
	 * 光源位置
	 */
	private Vector4f position = new Vector4f();
	/**
	 * 环境光
	 */
	private Vector3f ambient = new Vector3f();
	/**
	 * 散射光
	 */
	private Vector3f diffuse = new Vector3f();
	/**
	 * 高光
	 */
	private Vector3f specular = new Vector3f();
	
	/**
	 * 聚光灯或者平行光方向
	 */
	private Vector3f direction = new Vector3f();
	
	private float spotExponent;  
	
	private float spotCutoff; // (range: [0.0,90.0], 180.0)
	
	private float spotCosCutoff; // (range: [1.0,0.0],-1.0)
	
	/**
	 * 常数衰减系数
	 */
	private float constantAttenuation = 1;
	
	/**
	 * 线性衰减系数
	 */
	private float linearAttenuation = 1;
	
	/**
	 * 二次衰减系数
	 */
	private float quadraticAttenuation = 1;  
	
	public void glUniformLight(LightLocationHandler handler) {
		GL20.glUniform1i(handler.getEnableHandler(), LIGHTING && this.isEnable() ? 1 : 0);
		if(LIGHTING && this.isEnable()) {
			position.glUniform4f(handler.getPositionHandler());
			ambient.glUniform3f(handler.getAmbientHandler());
			diffuse.glUniform3f(handler.getDiffuseHandler());
			specular.glUniform3f(handler.getSpecularHandler());
			direction.glUniform3f(handler.getDirectionHandler());
			if(this.getPosition().getW() != 0) {
				GL20.glUniform1f(handler.getSpotExponentHandler(), spotExponent);
				GL20.glUniform1f(handler.getSpotCutoffHandler(), spotCutoff);
				GL20.glUniform1f(handler.getSpotCosCutoffHandler(), spotCosCutoff);
				GL20.glUniform1f(handler.getConstantAttenuationHandler(), constantAttenuation);
				GL20.glUniform1f(handler.getLinearAttenuationHandler(), linearAttenuation);
				GL20.glUniform1f(handler.getQuadraticAttenuationHandler(), quadraticAttenuation);
			}
		}
	}
	
	/**
	 * 获得结构
	 * @return
	 */
	public static String getLightStructString() {
		return "struct ece_LightSource {\n"+  
				"bool enable;\n" +
				"vec3 ambient;\n" +
				"vec3 diffuse;\n" +  
				"vec3 specular;\n" +  
				"vec4 position;\n" +
				"vec3 direction;\n" +  
				"float spotExponent;\n" +  
				"float spotCutoff;\n" +  
				"float spotCosCutoff;\n" +  
				"float constantAttenuation;\n" +  
				"float linearAttenuation;\n" +  
				"float quadraticAttenuation;\n" +  
			"};\n";
	}
	
	public void from(Light light) {
		this.enable = light.enable;
		this.ambient.set(light.ambient);
		this.constantAttenuation = light.constantAttenuation;
		this.diffuse.set(light.diffuse);
		this.direction.set(light.direction);
		this.linearAttenuation = light.linearAttenuation;
		this.position.set(light.position);
		this.quadraticAttenuation = light.quadraticAttenuation;
		this.specular.set(light.specular);
		this.spotCosCutoff = light.spotCosCutoff;
		this.spotCutoff = light.spotCutoff;
		this.spotExponent = light.spotExponent;
	}
	
	public boolean isEnable() {
		return enable;
	}

	public void setEnable(boolean enable) {
		this.enable = enable;
	}
	
	public float getSpotExponent() {
		return spotExponent;
	}

	public void setSpotExponent(float spotExponent) {
		this.spotExponent = spotExponent;
	}

	public Vector4f getPosition() {
		return position;
	}

	public Vector3f getAmbient() {
		return ambient;
	}

	public Vector3f getDiffuse() {
		return diffuse;
	}

	public Vector3f getSpecular() {
		return specular;
	}

	public Vector3f getDirection() {
		return direction;
	}

	public float getSpotCutoff() {
		return spotCutoff;
	}

	public float getSpotCosCutoff() {
		return spotCosCutoff;
	}

	public float getConstantAttenuation() {
		return constantAttenuation;
	}

	public float getLinearAttenuation() {
		return linearAttenuation;
	}

	public float getQuadraticAttenuation() {
		return quadraticAttenuation;
	}

	public void setSpotCutoff(float spotCutoff) {
		this.spotCutoff = spotCutoff;
		this.spotCosCutoff = (float) Math.cos(Math.toRadians(spotCutoff));
	}

	public void setConstantAttenuation(float constantAttenuation) {
		this.constantAttenuation = constantAttenuation;
	}

	public void setLinearAttenuation(float linearAttenuation) {
		this.linearAttenuation = linearAttenuation;
	}

	public void setQuadraticAttenuation(float quadraticAttenuation) {
		this.quadraticAttenuation = quadraticAttenuation;
	}
	
}
